#include "CPPPreprocessor.hpp"
#include "UnicodeConverter.hpp"
std::list<Level5::CPPPreprocessor::Token>* Level5::CPPPreprocessor::operator()(const char16_t* fileName)
{
	auto tokens(Level5::Preprocessor::operator()(fileName));
	if (!tokens)
		return nullptr;
	Token token(GetToken());
	while (!token.value.empty())
	{
		tokens->push_back(token);
		token = GetToken();
	}
	return tokens;
}
Level5::Preprocessor::Token Level5::CPPPreprocessor::GetToken()
{
	Token token(this);
	if (inFile.empty() || inFile.length() == index)
		return token;
	token.type = Preprocessor::Token::Type::Operator;
	while (true)
	{
		switch (inFile.at(index))
		{
		case 0:
			if (!token.value.empty())
				return token;
			token.type = Token::Type::Nul;
			break;
		case '\r':
			if (inFile.at(++index) != '\n')
			{
				++line;
				token.line = line;
				token.row = row = 1;
				if (!token.value.empty())
					return token;
				continue;
			}
			[[fallthrough]];
		case '\n':
			++line;
			token.line = line;
			token.row = row = 1;
			++index;
			if (!token.value.empty())
				return token;
			continue;
		case ' ':
		case '\t':
			++index;
			++row;
			if (!token.value.empty())
				return token;
			token.row = row;
			continue;
		case ':':
		{
			if (!token.value.empty())
				return token;
			if (inFile.at(++index) == U':')
			{
				++row;
				++index;
				token.value = U"::";
			}
			else
				token.value = U":";
			++row;
			return token;
		}
		case ';':
		case '(':
		case ')':
		case '[':
		case ']':
		case '{':
		case '}':
		case '~':
		case '?':
		case '.':
		case ',':
			if (!token.value.empty())
				return token;
			++row;
			token.value = inFile.at(index++);
			return token;
		case '-':
		{
			if (!token.value.empty())
				return token;
			switch (inFile.at(index))
			{
			case '>':
				token.value = U"->";
				break;
			case '-':
				token.value = U"--";
				break;
			case '=':
				token.value = U"-=";
				break;
			default:
				token.value = U"-";
				--index;
				--row;
			}
			index += 2;
			row += 2;
			return token;
		}
		case '+':
		{
			if (!token.value.empty())
				return token;
			switch (inFile.at(index))
			{
			case '+':
				token.value = U"++";
				break;
			case '=':
				token.value = U"+=";
				break;
			default:
				token.value = U"+";
				--index;
				--row;
			}
			index += 2;
			row += 2;
			return token;
		}
		case '*':
		case '/':
		case '%':
		case '^':
		case '!':
		case '=':
			if (!token.value.empty())
				return token;
			++row;
			token.value = inFile.at(index++);
			if (inFile.at(index) == '=')
			{
				++row;
				token.value += inFile.at(index++);
			}
			return token;
		case '>':
			if (!token.value.empty())
				return token;
			++row;
			token.value = inFile.at(index++);
			if (inFile.at(index) == '>')
			{
				token.value += '>';
				++row;
				++index;
			}
			if (inFile.at(index) == '>')
			{
				token.value += '>';
				++row;
				++index;
			}
			if (inFile.at(index) == '=')
			{
				token.value += '=';
				++row;
				++index;
			}
			return token;
		case '<':
		case '&':
		case '|':
			if (!token.value.empty())
				return token;
			token.value = inFile.at(index++);
			++row;
			if (inFile.at(index) == token.value.front())
			{
				token.value += inFile.at(index++);
				++row;
			}
			if (inFile.at(index) == '=')
			{
				token.value += '=';
				++row;
				++index;
			}
			return token;
			//case '$':
			//case '\\':
			//case '@':
			//case '#':
		case '\'':
		case '"':
			if (!token.value.empty())
				return token;
			token.type = Token::Type::String;
			token.value = inFile.at(index++);
			++row;
			while (inFile.at(index) != token.value.front())
			{
				if (inFile.at(index) == '\\')
				{
					++row;
					switch (inFile.at(++index))
					{
					case 'n':
						token.value += '\n';
						break;
					case 't':
						token.value += '\t';
						break;
					case 'r':
						token.value += '\r';
						break;
					case 'b':
						token.value += '\b';
						break;
					case '\\':
						token.value += '\\';
						break;
					case '"':
						token.value += '"';
						break;
					case '\'':
						token.value += '\'';
						break;
					default:
						token.value += '\\';
					}
				}
				else
					token.value += inFile.at(index);
				++index;
				++row;
			}
			token.value += inFile.at(index++);
			++row;
			return token;
		default:
			++row;
			token.type = Preprocessor::Token::Type::Id;
			token.value += inFile.at(index++);
		}
	}
	return token;
}